package com.imachen.ymcc.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.imachen.ymcc.doc.CourseDoc;
import com.imachen.ymcc.domain.*;
import com.imachen.ymcc.dto.CourseDto;
import com.imachen.ymcc.dto.CourseSendMessageDto;
import com.imachen.ymcc.dto.LoginContextDto;
import com.imachen.ymcc.dto.UserSmsDto;
import com.imachen.ymcc.enums.GlobalExceptionCode;
import com.imachen.ymcc.fegin.CourseEsFeignClien;
import com.imachen.ymcc.fegin.MediaFileFeignClien;
import com.imachen.ymcc.feign.UserFeign;
import com.imachen.ymcc.mapper.CourseMapper;
import com.imachen.ymcc.mapper.CourseTypeMapper;
import com.imachen.ymcc.result.JSONResult;
import com.imachen.ymcc.service.*;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.imachen.ymcc.util.AssertUtil;
import com.imachen.ymcc.utils.LoginContextUtil;
import com.imachen.ymcc.vo.CourseDetailVo;
import com.imachen.ymcc.vo.CourseInfoVo;
import com.imachen.ymcc.vo.CourseOrderVo;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;

import static com.imachen.ymcc.constants.MqConstants.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author imachen
 * @since 2022-09-30
 */
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    @Autowired
    private ITeacherService teacherService;

    @Autowired
    private ICourseDetailService courseDetailService;

    @Autowired
    private ICourseMarketService courseMarketService;

    @Autowired
    private ICourseResourceService courseResourceService;

    @Autowired
    private ICourseSummaryService courseSummaryService;

    @Autowired
    private ICourseTypeService courseTypeService;

    @Autowired
    private CourseMapper courseMapper;

    @Autowired
    private CourseTypeMapper courseTypeMapper;

    @Autowired
    private CourseEsFeignClien courseEsFeignClien;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private ICourseCollectService courseCollectService;

    @Autowired
    private UserFeign userFeign;

    @Autowired
    private ICourseChapterService courseChapterService;

    @Autowired
    private MediaFileFeignClien mediaFileFeignClien;

    /**
     * 新增课程
     *
     * @param courseDto
     */
    @Override
    public void save(CourseDto courseDto) {
        Course course = courseDto.getCourse();
        CourseDetail courseDetail = courseDto.getCourseDetail();
        CourseMarket courseMarket = courseDto.getCourseMarket();
        CourseResource courseResource = courseDto.getCourseResource();
        List<Long> teacherIds = courseDto.getTeacherIds();
        // 1.jsr303校验
        // 2.业务校验,课程名称是否重复
        Course courseTmp = selectByName(course.getName());
        AssertUtil.isNull(courseTmp, GlobalExceptionCode.COURSE_EXISTS_ERROR);
        // 3.保存课程表
        Long courseId = saveCourse(course, teacherIds);
        // 4.保存课程详情表
        courseDetail.setId(courseId);
        courseDetailService.insert(courseDetail);
        // 5.保存课程销售表
        courseMarket.setId(courseId);
        courseMarketService.insert(courseMarket);
        // 6.保存课程资源表
        courseResource.setCourseId(courseId);
        courseResourceService.insert(courseResource);
        // 7.初始化课程统计信息表
        initCourseSummary(courseId);
        // 8.保存课程和老师中间表
        courseMapper.insertCourseTeacher(courseId, teacherIds);
        // 9.修改课程对应的类型下的数量+1
        courseTypeMapper.updateTotalCountById(course.getCourseTypeId());
    }

    /**
     * 课程上架
     *
     * @param id
     */
    @Override
    public void onLineCourse(Long id) {
        // 1.查询课程信息
        Course course = selectById(id);
        // 2.业务校验
        AssertUtil.isNotNull(course, GlobalExceptionCode.COURSE_IS_NULL_ERROR);
        // 3.查询课程状态是否上架
        Boolean boo = Course.STATUS_ON == course.getStatus();
        AssertUtil.isFalse(boo, GlobalExceptionCode.COURSE_ON_LINE_ERROR);
        // 4.修改状态
        course.setStatus(Course.STATUS_ON);
        course.setOnlineTime(new Date());
        // 使用登录上下文工具类，获取到用户信息
        LoginContextDto context = LoginContextUtil.getContext();
        course.setLoginId(context.getId());
        course.setLoginUserName(context.getUsername());

        updateById(course);
        // 5.向es中添加数据
        // 5.1 查询相关数据
        CourseMarket courseMarket = courseMarketService.selectById(id);
        CourseSummary courseSummary = courseSummaryService.selectById(id);
        CourseType courseType = courseTypeService.selectById(course.getCourseTypeId());
        // 5.2.拷贝数据到doc对象中
        CourseDoc courseDoc = new CourseDoc();
        BeanUtils.copyProperties(course, courseDoc);
        BeanUtils.copyProperties(courseMarket, courseDoc);
        BeanUtils.copyProperties(courseSummary, courseDoc);
        courseDoc.setTypeName(courseType.getName());
        courseDoc.setCharge(courseMarket.getCharge() == 1 ? "免费" : "收费");

        // 6.调用搜索服务，保存数据到es
        JSONResult jsonResult = courseEsFeignClien.saveCourseEs(courseDoc);
        AssertUtil.isTrue(jsonResult.isSuccess(), GlobalExceptionCode.COURSE_RELEASE_ERROR);

        // 在收藏中根据courseId获取userId
        List<CourseCollect> courseCollects = courseCollectService.selectList(new EntityWrapper<CourseCollect>().eq("course_id", id));
        List<User> users = new ArrayList<>();
        courseCollects.forEach(e -> {
            JSONResult jsonResult1 = userFeign.selectOne(e.getUserId());
            String jsonString = JSONObject.toJSONString(jsonResult1.getData());
            User user = JSON.parseObject(jsonString, User.class);
            users.add(user);
        });
        // 根据获取到的userId集合 去批量查询该集合的所有phone
        // 7.课程推送成功给用户发送消息
        // 推送短信消息
        sendSmsMessage(courseDoc, users);
        // 推送邮箱信息
        sendEmailMessage(courseDoc, users);
        // 推送站内信信息
    }


    /**
     * 课程下架
     *
     * @param:
     */
    @Override
    public void offLineCourse(Long id) {
        // 查询课程信息
        Course course = selectById(id);
        // 2.业务校验
        AssertUtil.isNotNull(course, GlobalExceptionCode.COURSE_IS_NULL_ERROR);
        // 3.查询课程状态是否下架
        Boolean boo = Course.STATUS_OFF == course.getStatus();
        AssertUtil.isFalse(boo, GlobalExceptionCode.COURSE_OFF_LINE_ERROR);
        // 4.修改状态
        course.setStatus(Course.STATUS_OFF);
        updateById(course);
        // 5.删除es数据
        courseEsFeignClien.deleteCourseEs(id);

    }

    /**
     * 查询课程详情
     *
     * @param courseId
     * @return
     */
    @Override
    public CourseDetailVo getDetail(Long courseId) {
        // 查询课程信息
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course, GlobalExceptionCode.COURSE_IS_NULL_ERROR);
        // 判断该课程是否为上线状态
        Boolean boo = course.getStatus() == Course.STATUS_ON;
        AssertUtil.isTrue(boo, GlobalExceptionCode.COURSE_OFF_LINE_ERROR);
        // 查询课程的其他信息
        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);
        CourseDetail courseDetail = courseDetailService.selectById(courseId);
        // 查询讲师信息
        List<Teacher> teachers = courseMapper.selectTeacherByCourseId(courseId);
        // 查询课程章节信息
        List<CourseChapter> courseChapters = courseChapterService.selectList(new EntityWrapper<CourseChapter>().eq("course_id", courseId));
        // 将list转换为map
        Map<Long, CourseChapter> courseChapterMap = courseChapters.stream().collect(Collectors.toMap(CourseChapter::getId, courseChapter -> courseChapter));

        // 查询视频地址信息,转换类型
        JSONResult mediaFileResult = mediaFileFeignClien.getMediaFileByCourseId(courseId);
        AssertUtil.isTrue(mediaFileResult.isSuccess(), GlobalExceptionCode.COURSE_MEDIA_IS_NULL_ERROR);
        Object data = mediaFileResult.getData();
        AssertUtil.isNotNull(data, GlobalExceptionCode.COURSE_MEDIA_IS_NULL_ERROR);

        List<MediaFile> mediaFiles = JSON.parseArray(data.toString(), MediaFile.class);
        //判断该视频是否免费，用户是否够买, 免费和够买的视频才显示
        mediaFiles.forEach(mediaFile -> {
            mediaFile.setFileUrl(""); // 将视频地址设置为空
            // 在用户点击视频的时候才获取视频地址
            CourseChapter courseChapter = courseChapterMap.get(mediaFile.getChapterId());
            if (courseChapter != null) {
                courseChapter.getMediaFiles().add(mediaFile);
            }
        });
        return new CourseDetailVo(course, courseMarket, courseChapters, teachers, courseDetail, courseSummary);
    }


    /**
     * 获取课程订单信息
     *
     * @param courseIds
     * @return
     */
    @Override
    public CourseOrderVo getCourseOrderInfo(String courseIds) {
        // 校验课程id
        Set<Long> collect = Arrays.stream(courseIds.split(","))
                .filter(id -> !StringUtils.isEmpty(id))
                .map(id -> Long.valueOf(id))
                .collect(Collectors.toSet());
        // 判断校验完成后的id长度是否与传入一致
        Boolean boo = collect.size() == courseIds.split(",").length;
        AssertUtil.isTrue(boo, GlobalExceptionCode.ERROR);
        // 查询所有课程信息
        List<Long> courseIdsList = collect.stream().collect(Collectors.toList());
        List<Course> courses = selectBatchIds(courseIdsList);
        AssertUtil.isNotNull(courses, GlobalExceptionCode.ERROR);
        // 查询课程销售信息
        Map<Long, CourseMarket> courseMarketMap = courseMarketService.selectBatchIds(courseIdsList).stream().collect(Collectors.toMap(CourseMarket::getId, courseMarket -> courseMarket));

        // 创建课程订单信息对象
        CourseOrderVo courseOrderVo = new CourseOrderVo();
        // 创建课程信息对象
        List<CourseInfoVo> courseInfoVos = new ArrayList<>();

        courses.forEach(course -> {
            CourseInfoVo courseInfoVo = new CourseInfoVo();
            Boolean booCourse = Course.STATUS_ON == course.getStatus();
            AssertUtil.isTrue(booCourse, GlobalExceptionCode.ERROR);
            CourseMarket courseMarket = courseMarketMap.get(course.getId());
            AssertUtil.isNotNull(courseMarket, GlobalExceptionCode.ERROR);
            courseInfoVo.setCourse(course);
            courseInfoVo.setCourseMarket(courseMarket);
            // 设置课程所需的总金额
            courseOrderVo.setTotalAmount(courseOrderVo.getTotalAmount().add(courseMarket.getPrice()));
            // 添加课程信息
            courseInfoVos.add(courseInfoVo);
        });
        courseOrderVo.setCourseInfos(courseInfoVos);

        return courseOrderVo;
    }


    /**
     * 课程上架成功给用户推送短信消息
     *
     * @param courseDoc
     */
    private void sendSmsMessage(CourseDoc courseDoc, List<User> users) {
        CourseSendMessageDto courseSendMessageDto = new CourseSendMessageDto();
        courseSendMessageDto.setTitle("课程发布");
        courseSendMessageDto.setContent("亲爱的用户您好，最新课程 <a href='http://course.ymcc.com:6002/detail.html?courseId='" + courseDoc.getId() + "''> " + courseDoc.getName() + " </a> 发布啦，点击课程了解详情");

        users.forEach(e -> {
            UserSmsDto userSmsDto = new UserSmsDto();
            userSmsDto.setId(e.getId());
            userSmsDto.setPhone(e.getPhone());
            List<UserSmsDto> userSmsDtos = Arrays.asList(userSmsDto);
            courseSendMessageDto.setUserSmsDtos(userSmsDtos);
            rocketMQTemplate.sendOneWay(COURSE_SMS_TOPIC + ":" + COURSE_SMS_TAG, JSON.toJSONString(courseSendMessageDto));
        });
        // mq推送消息 单向
    }

    /**
     * 课程上架成功给用户推送邮箱消息
     *
     * @param courseDoc
     */
    private void sendEmailMessage(CourseDoc courseDoc, List<User> users) {
        CourseSendMessageDto courseSendMessageDto = new CourseSendMessageDto();
        courseSendMessageDto.setTitle("课程发布");
        courseSendMessageDto.setContent("亲爱的用户您好，最新课程 <a href='http://course.ymcc.com:6002/detail.html?courseId='" + courseDoc.getId() + "''> " + courseDoc.getName() + " </a> 发布啦，点击课程了解详情");
        users.forEach(e -> {
            UserSmsDto userSmsDto = new UserSmsDto();
            userSmsDto.setId(e.getId());
            userSmsDto.setEmail(e.getEmail());
            List<UserSmsDto> userSmsDtos = Arrays.asList(userSmsDto);
            courseSendMessageDto.setUserSmsDtos(userSmsDtos);
            rocketMQTemplate.sendOneWay(COURSE_EMAIL_TOPIC + ":" + COURSE_EMAIL_TAG, JSON.toJSONString(courseSendMessageDto));
        });
        // mq推送消息 单向
    }

    /**
     * 初始化课程统计信息表
     *
     * @param courseId
     */
    private void initCourseSummary(Long courseId) {
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(courseId);
        courseSummaryService.insert(courseSummary);
    }

    /**
     * 保存课程表
     *
     * @param course
     * @param teacherIds
     */
    private Long saveCourse(Course course, List<Long> teacherIds) {
        // 初始化参数，设置初始化状态为下架0
        course.setStatus(Course.STATUS_OFF);
        // 设置登录用户
        course.setLoginId(2l);
        course.setLoginUserName("imachen");
        // 查询讲师名称并设置
        List<Teacher> teachers = teacherService.selectBatchIds(teacherIds);
        // 得到讲师名称使用逗号进行拼接
        String teacherName = teachers.stream().map(Teacher::getName).collect(Collectors.joining(","));
        course.setTeacherNames(teacherName);
        insert(course);
        return course.getId();

    }

    /**
     * 根据name查询课程
     *
     * @param name
     * @return
     */
    private Course selectByName(String name) {
        return selectOne(new EntityWrapper<Course>().eq("name", name));
    }

}
